home *** CD-ROM | disk | FTP | other *** search
/ Windows Game Programming for Dummies (2nd Edition) / WinGamProgFD.iso / pc / DirectX SDK / DXSDK / samples / Multimedia / Direct3D / VolumeFog / readme.txt < prev    next >
Encoding:
Text File  |  2001-10-10  |  13.5 KB  |  277 lines

  1. //-----------------------------------------------------------------------------
  2. // Name: Volume Fog Direct3D Sample
  3. // 
  4. // Copyright (c) 1998-2001 Microsoft Corporation. All rights reserved.
  5. //-----------------------------------------------------------------------------
  6.  
  7.  
  8. Description
  9. ===========
  10.    The Volume Fog sample shows the per-pixel density volumetric rendering 
  11.    technique. The fog volume is modeled as a polygonal mesh, and the 
  12.    density of the fog at every pixel is computed by subtracting the front
  13.    side of the fog volume from the back side. The fog is mixed with the 
  14.    scene by accumulating an in/out test at every pixel -- that is, back-facing
  15.    fog polygons will add, while front-facing ones will subtract. If the value
  16.    is non zero, then the scene intersects the fog and the scene's depth value
  17.    is used. In order to get better results, this demo uses 12 bits of precision
  18.    by encoding high and low bits in different color channels. 
  19.  
  20.  
  21. Path
  22. ====
  23.    Source:     DXSDK\Samples\Multimedia\D3D\volumefog
  24.    Executable: DXSDK\Samples\Multimedia\D3D\Bin
  25.  
  26.  
  27. User's Guide
  28. ============
  29.    The following keys are implemented. 
  30.    <J>    Move object backward on the Z axis
  31.    <M>    Move Object forward on the z Axis
  32.    <H>    Move Object forward on the X axis
  33.    <K>    Move object backward on the X axis
  34.    <N>    Move object forward on the y axis
  35.    <Y>    Move object backward on the y axis
  36.  
  37.    Camera Controls:
  38.    <LEFT>    Slide Left
  39.    <RIGHT>   Slide Right
  40.    <DOWN>    Slide Down
  41.    <UP>      Slide Up
  42.    <W>       Move forward
  43.    <S>       Move backward
  44.    <NUMPAD8> Pitch Down
  45.    <NUMPAD2> Pitch Up
  46.    <NUMPAD4> Turn Right
  47.    <NUMPAD6> Turn Left
  48.    <NUMPAD9> Roll CW
  49.    <NUMPAD7> Roll CCW
  50.  
  51.    Mouse Controls:
  52.    Rotates Fog Volume.
  53.       
  54.  
  55. Programming Notes
  56. =================
  57. Introduction
  58.    The article "Volumetric Rendering in Real-Time," printed in the 2001 GDC 
  59.    Proceedings, covered the basis of volumetric depth rendering, but at the 
  60.    time of the writing, no pixel-shader-compliant hardware was available. 
  61.    This supplement describes a process designed to achieve two goals: to get 
  62.    more precision out of an 8 bit part, and to allow the creation of concave 
  63.    fog volumes.
  64.  
  65.  
  66. Handling Concavity
  67.    Computing the distance of fog for the convex case was relatively simple. 
  68.    Recall that the front side of the fog volume was subtracted away from the 
  69.    back side (where the depth is measured in number of units from the camera). 
  70.    Unfortunately, this does not work with concave fog volumes because at any 
  71.    given pixel, it may have two back sides and two front sides.  The solution 
  72.    is intuitive and has sound mathematical backing: sum all of the front 
  73.    sides and subtract them from the summed back sides. 
  74.  
  75.    So now, computing concavity is as simple as adding the multiple front 
  76.    sides and subtracting them from the multiple back sides. Clearly, a meager 
  77.    8 bits wonÆt be enough for this.  Every bit added would allow another 
  78.    summation and subtraction, and allow for more complex fog scenes.
  79.  
  80.    There is an important assumption being made about the fog volume. Is must 
  81.    be a continuous, orientable hull. That is, it cannot have any holes in 
  82.    it. Every ray cast through the volume must enter through hull the same 
  83.    number of times it exits.  
  84.  
  85. Getting Higher Precision
  86.    Although most 3D hardware handle 32 bits, it is really four 
  87.    8-bit channels. The way most hardware works today, there is only one place 
  88.    where the fog depths could be summed up: the alpha blender.  The alpha 
  89.    blender is typically used to blend on alpha textures by configuring the 
  90.    source destination to multiply against the source alpha, and the 
  91.    destination to multiply against the inverse alpha.  However, they can also 
  92.    be used to add (or subtract) the source and destination color channels. 
  93.    Unfortunately, there is no way to perform a carry operation here: If one 
  94.    channel would exceed 255 for a color value, it simply saturates to 255. 
  95.    In order to perform higher bit precision additions on the alpha blending 
  96.    unit, the incoming data has to be formatted in a way which is compatible 
  97.    with the way the alpha blender adds. To do this, the color channels can 
  98.    hold different bits of the actual result, and most importantly, be allowed 
  99.    some overlap in their bits. 
  100.  
  101.    This sample uses the following scheme: The red channel will contain the 
  102.    upper 8 bits, and the blue channel will contain the lower 4 plus 3 carry 
  103.    spots. The upper bit should not be used for reasons which are discussed 
  104.    later. So the actual value encoded is Red*16+Blue.  Now, the alpha blender 
  105.    will add multiple values in this format correctly up to 8 times before 
  106.    there is any possibility of a carry bit not propagating. This limits the 
  107.    fog hulls to ones which do not have concavity where looking on any 
  108.    direction a ray might pass in and out of the volume more than 8 times. 
  109.    Encoding the bits in which will be added cannot be done with a pixel 
  110.    shader. There are two primary limitations. First, the color interpolators 
  111.    are 8 bit as well. Since the depth is computed on a per vertex level, this 
  112.    wonÆt let higher bit values into the independent color channels. Even if 
  113.    the color channel had a higher precision, the pixel shader has no 
  114.    instruction to capture the lower bits of a higher bit value.
  115.    The alternative is to use a texture to hold the encoded depths. The 
  116.    advantage of this is twofold. First, texture interpolaters have much 
  117.    higher precision than color interpolaters, and second, no pixel shader is 
  118.    needed for initial step of summing the font and back sides of the fog 
  119.    volume. It should be possible, on parts with at least 12 bits precision in 
  120.    the pixel shader, to emded the precision in a texture registers instead.
  121.    Unfortunately, most hardware limits the dimensions of textures. 4096 is a 
  122.    typical limitation. This amounts to 12 bits of precision to be encoded in 
  123.    the texture. 12 bits, however, is vastly superior to 8 bits and can make 
  124.    all the difference to making fog volumes practical. More precision could 
  125.    be obtained by making the texture a sliding window, and breaking the 
  126.    object into sizable chunks which would index into that depth, but this 
  127.    sample does not do this.
  128.  
  129. Setting it all Up
  130.    Three important details remain: The actual summing of the fog sides, 
  131.    compensating for objects inside the fog, and the final subtraction.
  132.    The summing is done in three steps. 
  133.    
  134.    First, the scene needs to be rendered 
  135.    to set a Z buffer. This will prevent fog pixels from being drawn which are 
  136.    behind some totally occluding objects. In a real application, this z could 
  137.    be shared from the pass which draws the geometry. The Z is then write 
  138.    disabled so that fog writes will not update the z buffer. 
  139.    
  140.    After this, the summing is exactly as expected. The app simply draws all 
  141.    the forward facing polygons in one buffer, adding up their results, and 
  142.    then draws all the backward facing polygons in another buffer. There is 
  143.    one potential problem, however. In order to sum the depths of the fog 
  144.    volume, the alpha blend constants need to be set to one for the 
  145.    destination and one for the source, thereby adding the incoming pixel with 
  146.    the one already in the buffer.
  147.    Unfortunately, this does not take into account objects inside the fog that 
  148.    are acting as a surrogate fog cover.  In this case, the scene itself must 
  149.    be added to scene since the far end of the fog would have been rejected by 
  150.    the Z test. 
  151.  
  152.    At first, this looks like an easy solution. In the previous article, the 
  153.    buffers were set up so that they were initialized to the sceneÆs depth 
  154.    value. This way, fog depth values would replace any depth value in the 
  155.    scene if they were in front of it (i.e. the Z test succeeds) -- but if no 
  156.    fog was present the scene would act as the fog cover.
  157.    
  158.    This cannot be done for general concavity, however.  While technically 
  159.    correct in the convex case, in the concave case there may be pixels at 
  160.    which the fog volumes are rendered multiple times on the front side and 
  161.    multiple sides on the backside. For these pixels, if the there was part 
  162.    of an object in between fog layers than the front buffer would be the sum 
  163.    of n front sides, and the back side would be sum of n-1 back sides. But 
  164.    since the fog cover was replaced by the fog, there are now more entry 
  165.    points then exit points. The result is painfully obvious: parts of the 
  166.    scene suddenly loose all fog when they should have some.
  167.  
  168.    The solution requires knowing which scenarios where the sceneÆs w depth 
  169.    should be added and which scenarios the sceneÆs w depth should be ignored. 
  170.    Fortunately, this is not difficult to find. The only situation where the 
  171.    sceneÆs w depth should be added to the total fog depth are those pixels 
  172.    where the object is in between the front side of a fog volume and its 
  173.    corresponding backside.  
  174.  
  175.    The above question can be thought of as asking the question: did the ray ever 
  176.    leave the fog volume? Since the fog hulls are required to be continuous, 
  177.    then if the answer is no then part of the scene must have blocked the ray.  
  178.    This test can be performed by a standard inside outside test.
  179.    
  180.    To perform an inside/outside test each time a fog pixel is rendered, the 
  181.    alpha value is incremented. If the alpha values of the far fog distances 
  182.    is subtracted to the corresponding point on the near fog distance, then 
  183.    values greater then 1 indicate the ray stopped inside the volume. Values 
  184.    of 0 indicate that the ray left the fog volume.
  185.    
  186.    To set this test up, the alpha buffer of the near and far w depth buffers 
  187.    must be cleared to 0.  Each time a fog pixel is rendered, the alpha will 
  188.    be incremented by the hex value 0x10. This value was used because the 
  189.    pixel shader must perform a 1 or 0 logical operation. A small positive 
  190.    value must be mapped to 1.0 in the pixel shader, a step which requires 
  191.    multiple shifts. Due to instruction count restraints the intial value 
  192.    has to be at least 0x10 for the shifts to saturate a non-zero value to one.
  193.    The rest is straightforward: all the front sides and all the backsides 
  194.    are summed up in their independent buffers. The scene is also drawn in its 
  195.    own buffer. Then all three buffers are ran through the final pass where 
  196.    the sceneÆs w depth is added on only if the differences of the alpha 
  197.    values is not 0.
  198.  
  199.    This requires a lengthy pixel shader. A great deal of care must be taken 
  200.    to avoid potential precision pitfalls. The following pixel shader performs 
  201.    the required math, although it requires every instruction slot of the 
  202.    pixel shader and nearly every register. Unfortunately, with no carry bit, 
  203.    there is no way to achieve a full 8 bit value at the end of the 
  204.    computation, so it must settle for 8.
  205.  
  206. ps.1.1
  207. def c1, 1.0f,0.0f,0.0f,0.0f
  208. def c4, 0.0f,0.0f,1.0f,0.0f
  209.  
  210. tex t0        // near buffer B
  211. tex t1        // far buffer A
  212. tex t2              // scene buffer C
  213.  
  214. // input:
  215. // b    = low bits (a)  (4 bits) 
  216. // r   = high bits (b) (8 bits)
  217. // intermediate output: 
  218. // r1.b  = (a1 - a2) (can't be greater than 7 bits set )
  219. // r1.r   = (b1 - b2)
  220.  
  221. sub r1.rgb,t1,t0
  222. +sub_4x r1.a,t0,t1      //If this value is non zero, then 
  223. mov_4x r0.a,r1.a        //the were not as many backs as 
  224. mad r1.rgb,r0.a,t2,r1 //front and must add in the scene
  225. dp3 t0.rgba,r1,c4        // move red component into alpha
  226.  
  227. // Need to shift r1.rgb 6 bits.  This could saturate
  228. // to 255 if any other bits are set, but that is fine
  229. // because in this case, the end result of the subtract 
  230. // would have to be saturated since we can't be
  231. // subtracting more than 127
  232. mov_x4 r1.rgb,r1
  233. dp3_x4 t1.rgba,r1,c1   // move into the alpha
  234. add_x2  r0.a,t0.a,t1.a // the subtract was in 0-127
  235. mov_d2   r0.a,r0.a     // chop off last bit else banding
  236. +mov r0.rgb,c3         // load the fog color
  237.  
  238.  
  239.    This pixel shader gives an alpha value which represents the density of fog, 
  240.    and loads the fog color constant into the color channels. The Alpha 
  241.    Blending stage can now be used to blend on the fog.  
  242.  
  243.    Finally, there is one situation which can cause serious problems: 
  244.    clipping. If a part of the fog volume is clipped away by the camera 
  245.    because the camera is partially in the fog, then part of the scene might 
  246.    be in the fog. Previously, it was assumed the camera was either entirely 
  247.    all the way in, or all the way out of the fog. This may not always be the 
  248.    case.
  249.  
  250.    An alternative solution is to not allow polygons to get clipped. The 
  251.    vertex shader can detect vertices which would get clipped away and snap 
  252.    them to the near clip plane. The following vertex shader clips w depths 
  253.    to the near clip plane, and z depths to zero.
  254.  
  255. // transform position into projection space
  256. m4x4 r0,v0,c8
  257. max r0.z,c40.z,r0.z       //clamp to 0
  258. max r0.w,c12.x,r0.w     //clamp to near clip plane
  259. mov oPos,r0
  260.  
  261. // Subtract the Near clipping plane
  262. add r0.w,r0.w,-c12.x 
  263.  
  264. // Scale to give us the far clipping plane
  265. mul r0.w,r0.w,c12.y
  266.  
  267. // load depth into texture, donÆt care about y
  268. mov oT0.xy,r0.w
  269.  
  270.  
  271.    
  272.    This sample makes use of common DirectX code (consisting of helper functions,
  273.    etc.) that is shared with other samples on the DirectX SDK. All common
  274.    headers and source code can be found in the following directory:
  275.       DXSDK\Samples\Multimedia\Common
  276.  
  277.